#pragma once
#include<iostream>
#include<ctime>
#include"Epoll.hpp"
#include"Socket.hpp"
#include"nocopy.hpp"
#include"Common.hpp"
#include<memory>
#include<string>
#include<vector>
#include<functional>
#include<unordered_map>

class Connection;
class TcpServer;

uint32_t EVEN_IN= (EPOLLIN|EPOLLET);
uint32_t EVEN_OUT= (EPOLLOUT|EPOLLET) ;
using func_t =std::function<void(std::shared_ptr<Connection>) >;



class Connection
{
public:
    Connection(int sock):_sock(sock)
    {}
    ~Connection()
    {
    }
    void SetHandler(func_t recv_cb,func_t send_cb,func_t except_cb)
    {
        _recv_cb=recv_cb;
        _send_cb=send_cb;
        _except_cb=except_cb;
    }

    int SockFd()
    {
        return _sock;
    }
    void AppendInBuffer(std::string info)
    {
        _inbuffer+=info;
    }
    void AppendOutBuffer(std::string& info)
    {
        _outbuffer+=info;
    }
    std::string &OutBuffer()
    {
        return _outbuffer;
    }
    std::string &InBuffer()
    {
        return _inbuffer;
    }
private:
    int _sock;
    std::string _inbuffer;//缓冲区
    std::string _outbuffer;
public:
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;

    //添加一个回指指针
    std::shared_ptr<TcpServer> _tcp_server_ptr;
    std::string _ip;
    uint16_t _port;

};

static const int num=64;
class TcpServer:public nocopy{

public:
    TcpServer(uint16_t port):_port(port),quit(false),_epoller_ptr(new Epoller()),_listensock_ptr(new Sock())
    {
        _listensock_ptr->Socket();
        SetNonBlockOrDie(_listensock_ptr->Fd());
        _listensock_ptr->Bind(_port);
        _listensock_ptr->Listen();
        lg(Fatal,"listen sock create success:%d\n",_listensock_ptr->Fd());

    }

    void Init()
    {
        
        _listensock_ptr->Bind(_port);
        _listensock_ptr->Listen();
        lg(Info,"create listen socket success:%d\n",_listensock_ptr->Fd());
        AddConnection(_listensock_ptr->Fd(),EVEN_IN,std::bind(&TcpServer::Accepter,this,std::placeholders::_1),nullptr,nullptr);
        
    }
    // void Start()
    // {
    //     quit=false;
    //     // 1、我们添加对应的事件，除了要加到内核中，fd,event
    //     // 2、给listensock 也建立一个connection 对象 ，将listensock 添加到connection 中，同时，listensock Connection也放入_connections

       
    //     while(!quit)
    //     {
    //         int n=_epoller_ptr->EpolerWait(revs,num,);

    //     }
    // }
    //
    void AddConnection(int sock,uint32_t event,func_t recv_cb,func_t send_cb,func_t except_cb)
    {
        // 1、我们添加对应的事件，除了要加到内核中，fd,event
        _epoller_ptr->EpollUpdate(EPOLL_CTL_ADD,sock,event);
        // 2、给listensock 也建立一个connection 对象 ，将listensock 添加到connection 中，同时，listensock Connection也放入_connections
        std::shared_ptr<Connection>new_connection=std::make_shared<Connection>(sock,std::shared_ptr<TcpServer>(this));
        new_connection->SetHandler(recv_cb,send_cb,except_cb);
        
        //添加到unordered_map
        _connections.insert(std::make_pair(sock,new_connection));
        //添加对应的事件，除了要加到内核中，fd event
        _epoller_ptr->EpollUpdate(EPOLL_CTL_ADD,sock,event);
        
    }
    void Dispatcher(int timeout)
    {
        int n=_epoller_ptr->EpolerWait(revs,num,timeout);
        for(int i=0;i<n;i++)
        {
            uint32_t events=revs[i].events;
            int sock=revs[i].data.fd;
            //统一把事件异常转换为读写问题
            if(events& EPOLLERR)
                events|=(EPOLLIN|EPOLLOUT);
            if(events|EPOLLHUP)
                events|=(EPOLLIN|EPOLLOUT);
            
            //只需要处理EPOLLIN EPOLLOUT
            if((events& EPOLLIN)&&IsConnectionSafe(sock))
            {
                if(_connections[sock]->_recv_cb)
                    _connections[sock]->_recv_cb(_connections[sock]);
            }            
        }

    }
    //链接管理器
    void Accepter(std::shared_ptr<Connection>connection)
    {
        
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int sock=::accept(connection->SockFd(),(sockaddr*)&peer,&len);
            if(sock>0)
            {
                uint16_t peerport=ntohs(peer.sin_port);
                char ipbuf[1024];
                inet_ntop(AF_INET,&peer.sin_addr,ipbuf,sizeof(ipbuf));

                SetNonBlockOrDie(sock);
                AddConnection(sock,EVEN_IN,std::bind(&TcpServer::Recver,this,std::placeholders::_1),nullptr,nullptr);
            }
            else {
                if(errno==EWOULDBLOCK) break;
                else if(errno==EINTR)   continue;
                else break;
            }
        }
    }
    //事件管理器
    void Recver(std::shared_ptr<Connection> connection)
    {
        std::cout<<"got you!!,sockfd:"<<connection->SockFd()<<std::endl;
        int sock=connection->SockFd();
        while(true)
        {
            char buffer[128];
            memset(buffer,0,sizeof(buffer));
            ssize_t n=recv(sock,buffer,sizeof(buffer)-1,0);
            if(n>0)
            {
                connection->AppendInBuffer(buffer);

            }
            else if(n==0)
            {
                lg(Info,"sockfd:%d,client info %s:%d quit",connection->_ip.c_str(),connection->_port);
                connection->_except_cb(connection);
            }
            else{
                if(errno==EWOULDBLOCK)
                    break;
                else if(errno==EINTR)
                    continue;
                else{
                    lg(Warning,"sockfd:%d,client info%s:%d recv erro...",sock,connection->_ip.c_str(),connection->_port);
                    connection->_except_cb(connection);
                    return ;
                }
                

            }
        }
    }
    //事件管理器
    void Sender(std::weak_ptr<Connection> conn)
    {
        auto connection=conn.lock();
        int sock=connection->SockFd();
        auto outbuffer=connection->OutBuffer();
        while(true)
        {
            char buffer[128];
            memset(buffer,0,sizeof(buffer));
            ssize_t n=recv(sock,buffer,sizeof(buffer)-1,0);
            if(n>0)
            {
                connection->AppendInBuffer(buffer);

            }
            else if(n==0)
            {
                lg(Info,"sock:%d,client info%d:%s",sock,connection->_ip.c_str(),connection->_port);
                connection->_except_cb(connection);
                return ;
            }
            else{
                if(errno==EWOULDBLOCK)
                    break;
                else if(errno==EINTR)
                    continue;
                else{
                    lg(Warning,"sockfd:%d,client info%s:%d recv erro...",sock,connection->_ip.c_str(),connection->_port);
                    connection->_except_cb(connection);
                    return ;
                }
            }
        }
        if(!outbuffer.empty())
        {
            EnableEvent(connection->SockFd(),true,true);

        }
        else{
            //关闭对写事件的关心
            EnableEvent(connection->SockFd(),true,false);
        }
    }
    void Exceptr(std::shared_ptr<Connection> connection)
    {
        
        lg(Warning,"Exceptr Handler sockfd:%d,client info %s:%d",connection->SockFd(),connection->_ip.c_str(),connection->_port);
        //移除对特定fd关心
        _epoller_ptr->EpollUpdate(EPOLL_CTL_DEL,connection->SockFd(),0);
        //关闭对异常的文件描述符
        close(connection->SockFd());
        //从unordered_mao中移除
        _connections.erase(connection->SockFd());
    }
    bool IsConnectionSafe(int fd)
    {
        auto iter=_connections.find(fd);
        if(iter==_connections.end())
            return false;
        else return true;
    }
    void EnableEvent(int sock,bool readable,bool writeable)
    {
        uint32_t events=0;
        events |=((readable?EPOLLIN:0)|(writeable?EPOLLOUT:0)|EPOLLET);
        _epoller_ptr->EpollUpdate(EPOLL_CTL_MOD,sock,events);
    }
    void Loop()
    {
        quit-false;
        while(!quit)
        {
            Dispatcher(3000);
            PrintConnection();
        }
        quit=true;
    }
    void PrintConnection()
    {
        std::cout<<"_connection list fd is:";
        for(auto& connection:_connections)
        {
            std::cout<<connection.second->SockFd();
            
        }
        std::cout<<std::endl;
    }


private:
    std::shared_ptr<Epoller>_epoller_ptr;//内核
    std::shared_ptr<Sock> _listensock_ptr;//监听
    std::unordered_map<int,std::shared_ptr<Connection>> _connections;
    uint16_t _port;
    struct epoll_event revs[num];
    bool quit;
    func_t Onmessage;
};